package com.intelligencesoft.pss.utils.auth;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class Base64 {
	private static final byte CR = '\r';
	private static final byte LF = '\n';

	public static char[] encode(byte[] data) {
		return encode(data, 0, data.length);
	}

	public static char[] encode(byte[] data, int offset, int length) {
		byte[] buffer = new byte[length];
		System.arraycopy(data, offset, buffer, 0, length);

		char[] out = new char[((buffer.length + 2) / 3) * 4];
		for (int i = 0, index = 0; i < buffer.length; i += 3, index += 4) {
			boolean quad = false;
			boolean trip = false;

			int val = (0xFF & (int) buffer[i]);
			val <<= 8;
			if ((i + 1) < buffer.length) {
				val |= (0xFF & (int) buffer[i + 1]);
				trip = true;
			}
			val <<= 8;
			if ((i + 2) < buffer.length) {
				val |= (0xFF & (int) buffer[i + 2]);
				quad = true;
			}
			out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
			val >>= 6;
			out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
			val >>= 6;
			out[index + 1] = alphabet[val & 0x3F];
			val >>= 6;
			out[index + 0] = alphabet[val & 0x3F];
		}
		return out;
	}

	public static byte[] decode(char[] data) throws Exception {
		return decode(data, 0, data.length);
	}

	public static byte[] decode(String data) throws Exception {
		return decode(data.toCharArray());
	}

	public static byte[] decode(char[] data, int offset, int length)
			throws Exception {
		char[] buffer = new char[length];
		System.arraycopy(data, offset, buffer, 0, length);

		int tempLen = buffer.length;
		for (int ix = 0; ix < buffer.length; ix++) {
			int value = codes[buffer[ix] & 0xFF];
			if ((value < 0) && (buffer[ix] != 61)) {
				--tempLen;
			}
		}

		int len = ((tempLen + 3) / 4) * 3;
		if (tempLen > 0 && buffer[tempLen - 1] == '=') {
			--len;
		}
		if (tempLen > 1 && buffer[tempLen - 2] == '=') {
			--len;
		}
		byte[] out = new byte[len];

		int shift = 0;
		int accum = 0;
		int index = 0;

		for (int ix = 0; ix < buffer.length; ix++) {
			int value = codes[buffer[ix] & 0xFF];
			if (value >= 0) {
				accum <<= 6;
				shift += 6;
				accum |= value;
				if (shift >= 8) {
					shift -= 8;
					out[index++] = (byte) ((accum >> shift) & 0xff);
				}
			}
		}

//		if (index != out.length) {
//			System.out.println(index);
//			System.out.println(out.length);
//		}

		return out;
	}

	public static String removeCRLFAndBlank(String str) {
		StringBuffer buffer = new StringBuffer();
		char[] data = str.toCharArray();
		for (int i = 0; i < data.length; i++) {
			if (data[i] == ' ' || data[i] == '\r' || data[i] == '\n') {
				continue;
			}
			buffer.append(data[i]);
		}
		return buffer.toString();
	}

	static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
			.toCharArray();
	static private byte[] codes = new byte[256];
	static {
		for (int i = 0; i < 256; i++) {
			codes[i] = -1;
		}
		for (int i = 'A'; i <= 'Z'; i++) {
			codes[i] = (byte) (i - 'A');
		}
		for (int i = 'a'; i <= 'z'; i++) {
			codes[i] = (byte) (26 + i - 'a');
		}
		for (int i = '0'; i <= '9'; i++) {
			codes[i] = (byte) (52 + i - '0');
		}
		codes['+'] = 62;
		codes['/'] = 63;
	}

	public static byte[] decode(String start, String end, char[] buffer)
			throws Exception {
		return Base64.decode(start, end, buffer, 0, buffer.length);
	}

	public static byte[] decode(String start, String end, char[] buffer,
			int offset, int length) throws Exception {
		String line = new String(buffer, offset, length);
		if (line.startsWith(start)) {
			line = line.substring(start.length());
		}

		byte[] tempBuffer = line.getBytes();
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		DataOutputStream out = new DataOutputStream(bout);
		for (int i = 0; i < tempBuffer.length; i++) {
			byte b = tempBuffer[i];
			if (b != (byte) CR && b != (byte) LF) {
				try {
					out.writeByte(b);
				} catch (IOException ex) {
				}
			}
		}
		tempBuffer = bout.toByteArray();

		line = new String(tempBuffer);
		if (line.endsWith(end)) {
			line = line.substring(0, line.length() - end.length());
		}

		byte[] decoded = null;
		decoded = Base64.decode(line.toCharArray());
		return decoded;
	}

	public static char[] encode(String start, String end, byte[] inBuffer) {
		return Base64.encode(start, end, inBuffer, 0, inBuffer.length);
	}

	public static char[] encode(String start, String end, byte[] inBuffer,
			int offset, int length) {
		try {
			char[] buffer = Base64.encode(inBuffer, offset, length);
			StringBuffer sb = new StringBuffer();
			sb = sb.append(start);
			sb = sb.append((char) CR);
			sb = sb.append((char) LF);
			int count = buffer.length / 64;
			int i = 0;
			for (i = 0; i < count; i++) {
				char[] temp = new char[64];
				System.arraycopy(buffer, i * 64, temp, 0, 64);
				sb = sb.append(new String(temp));
				sb = sb.append((char) CR);
				sb = sb.append((char) LF);
			}
			int reserved = buffer.length % 64;
			char[] temp = new char[reserved];
			System.arraycopy(buffer, i * 64, temp, 0, reserved);
			sb = sb.append(new String(temp));
			if (reserved != 0) {
				sb = sb.append((char) CR);
				sb = sb.append((char) LF);
			}

			sb = sb.append(end);
			sb = sb.append((char) CR);
			sb = sb.append((char) LF);
			return sb.toString().toCharArray();
		} catch (Exception e) {
			return null;
		}
	}
}
